package io.kiki.stack.netty.userProcessor;

import io.kiki.stack.netty.channelManager.ChannelContext;
import io.kiki.stack.netty.lifeCycle.LifeCycle;
import io.kiki.stack.netty.processor.AsyncContext;
import io.kiki.stack.netty.processor.BizContext;

import java.util.concurrent.Executor;


public interface UserProcessor<T> extends LifeCycle {

    /**
     * Pre handle request, to avoid expose {@link ChannelContext} directly to biz handle request logic.
     */
    BizContext preHandleRequest(ChannelContext channelContext, T request);


    void asyncHandleRequest(BizContext bizContext, AsyncContext asyncContext, T request);

    Object syncHandleRequest(BizContext bizContext, T request) throws Exception;

    /**
     * The class name of user request.
     * Use String type to avoid classloader problem.
     *
     * @return interested request's class name
     */
    String interest();


    Executor getExecutor();

    /**
     * Get business class loader
     */
    ClassLoader getBizClassLoader();

    /**
     * Whether deserialize and process biz logic in io thread.
     * Notice: If return true, this will have a strong impact on performance.
     *
     * @return true for processing in io thread
     */
    boolean processInIOThread();

    /**
     * Whether handle request timeout automatically, we call this fail fast processing when detect timeout.
     * <p>
     * Notice: If you do not want to enable this feature, you need to override this method to return false,
     * and then call {@link BizContext#isRequestTimeout()} to check by yourself if you want.
     *
     * @return true if you want to enable fail fast processing, otherwise return false
     */
    boolean timeoutDiscard();

    /**
     * Use this method to get the executor selector.
     */
    ExecutorSelector getExecutorSelector();

    /**
     * Use this method to set executor selector.
     */
    void setExecutorSelector(ExecutorSelector executorSelector);

    /**
     * Executor selector interface.
     * You can implement this and then provide a {@link ExecutorSelector} using method {@link #setExecutorSelector(ExecutorSelector)}
     */
    interface ExecutorSelector {
        Executor select(String requestClass, Object requestHeader);
    }
}
